import time
from datetime import datetime, timedelta

from flask import abort, jsonify
from flask import current_app, redirect, url_for
from flask import g
from flask import render_template
from flask import request
from flask import session

from info import db
from info.constants import USER_COLLECTION_MAX_NEWS, QINIU_DOMIN_PREFIX
from info.models import User, News, Category
from info.modules.admin import admin_blu
from info.utils.common import user_login_data, file_upload

# 创建视图函数 后台登陆
from info.utils.response_code import RET, error_map


@admin_blu.route("/login", methods=['GET', 'POST'])
def login():
    # GET请求展示页面
    if request.method == "GET":
        # ２．取出session中的数据，判断登录状态
        user_id = session.get("user_id")
        is_admin = session.get("is_admin")
        if user_id and is_admin:  # 管理员已经登录，重定向到后台首页
            return redirect(url_for("admin.index"))
        # 没登录就到登录页面
        return render_template("admin/login.html")

    # POST请求获取参数
    username = request.form.get("username")
    password = request.form.get("password")

    # 校验参数
    if not all([username, password]):
        return render_template("admin/login.html", errmsg="参数不足")

    # 查询用户模型 必须是管理员才能登陆
    try:
        user = User.query.filter(User.mobile == username, User.is_admin == True).first()
    except BaseException as e:
        current_app.logger.error(e)
        return render_template("admin/login.html", errmsg="数据库错误")

    if not user:
        return render_template("admin/login.html", errmsg="用户不存在")

    # 校验密码
    if not user.check_password(password):
        return render_template("admin/login.html", errmsg="用户/密码错误")

    # １．如果登录成功　记录用户信息
    session['user_id'] = user.id
    session['is_admin'] = True

    # 如果成功，则重定向到后台首页
    return redirect(url_for("admin.index"))


# 后台主页
@admin_blu.route('/')
@user_login_data
def index():
    # 走到此管理员一定是登陆的　管理员信息直接渲染到模板
    return render_template("admin/index.html", user=g.user.to_dict())


# 退出登录
@admin_blu.route('/logout')
def logout():
    # ３．删除session中的数据
    session.pop("user_id", None)
    session.pop("is_admin", None)
    return redirect(url_for('admin.login'))


# 用户统计
@admin_blu.route('/user_count')
def user_count():
    # 用户总数
    total_count = 0
    try:
        total_count = User.query.filter(User.is_admin == False).count()
    except BaseException as e:
        current_app.logger.error(e)

    # 获取当前日期对应的年和月
    t = time.localtime()

    # 构建日期字符串　"2018-11-01"
    mon_data_str = "%d-%02d-01" % (t.tm_year, t.tm_mon)

    # 将日期字符串　转换为　日期对象
    mon_data = datetime.strptime(mon_data_str, "%Y-%m-%d")

    # 月新增人数　注册时间>=本月一号0点
    mon_count = 0
    try:
        mon_count = User.query.filter(User.is_admin == False, User.create_time >= mon_data).count()
    except BaseException as e:
        current_app.logger.error(e)

    # 日新增人数 注册时间>=本年本月本日0点
    day_count = 0
    # 构建日期字符串 取出当前时间对应的年月日
    day_date_str = "%d-%02d-%02d" % (t.tm_year, t.tm_mon, t.tm_mday)
    # 转为日期对象
    day_date = datetime.strptime(day_date_str, "%Y-%m-%d")
    try:
        day_count = User.query.filter(User.is_admin == False, User.create_time >= day_date).count()
    except BaseException as e:
        current_app.logger.error(e)

    # 日注册人数统计，取某日的注册人数 >= 当日零点 <次日零点
    active_count = []  # 存放每天的注册人数
    active_time = []  # 存放对应注册人数的当天

    for i in range(0, 30):
        begin_data = day_date - timedelta(days=i)  # 当天零点减去一天，前天
        end_data = day_date + timedelta(days=1) - timedelta(days=i)  # 当天零点加一天，明天，减一天当天。
        try:
            # 一天的注册量
            one_day_count = User.query.filter(User.is_admin == False, User.create_time >= begin_data,
                                              User.create_time <= end_data).count()
            # 当天往前一个月每天的注册量添加到列表中
            active_count.append(one_day_count)

            # 获取当日日期对象对应的字符串形式
            one_day_str = begin_data.strftime("%Y-%m-%d")
            active_time.append(one_day_str)  # ["2018-11-19"] 注意存在列表中的是字符串形式
        except BaseException as e:
            current_app.logger.error(e)

    # 数据和时间倒序
    active_time.reverse()
    active_count.reverse()

    data = {
        "total_count": total_count,
        "mon_count": mon_count,
        "day_count": day_count,
        "active_count": active_count,
        "active_time": active_time
    }
    return render_template("admin/user_count.html", data=data)


# 用户列表
@admin_blu.route("/user_list")
def user_list():
    # 请求钩子已经判断是否是管理员登录

    # 获取参数获取请求的第几页  默认为1
    p = request.args.get("p", 1)
    # 校验参数
    try:
        p = int(p)
    except BaseException as e:
        current_app.logger.error(e)
        return abort(403)

    # 查询所有的用户
    try:
        pn = User.query.filter(User.is_admin == False).paginate(p, USER_COLLECTION_MAX_NEWS)
    except BaseException as e:
        current_app.logger.error(e)

    # 转换数据
    data = {
        "user_list": [user.to_admin_dict() for user in pn.items],  # 取出所有数据放到列表中，传给页面遍历
        "cur_page": pn.page,  # 当前页码
        "total_page": pn.pages  # 总页数
    }

    # 传入模板渲染
    return render_template("admin/user_list.html", data=data)


# 新闻审核
@admin_blu.route("/news_review")
def news_review():
    # 请求钩子已经判断是否是管理员登录

    # 获取参数获取请求的第几页  默认为1
    p = request.args.get("p", 1)
    # 获取关键字
    keyword = request.args.get("keyword")

    # 校验参数
    try:
        p = int(p)
    except BaseException as e:
        current_app.logger.error(e)
        return abort(403)

    filter_list = []
    # 判断是否设置了关键字
    if keyword:
        # 有关键字就   添加到列表中    新闻标题中含有此keyword的新闻
        filter_list.append(News.title.contains(keyword))

    # 查询所有的新闻
    try:
        # 有条件按照条件，没有就查询所有
        pn = News.query.filter(*filter_list).paginate(p, USER_COLLECTION_MAX_NEWS)
    except BaseException as e:
        current_app.logger.error(e)

    # 转换数据
    data = {
        "news_list": [news.to_review_dict() for news in pn.items],  # 取出所有数据放到列表中，传给页面遍历
        "cur_page": pn.page,  # 当前页码
        "total_page": pn.pages  # 总页数
    }

    # 传入模板渲染
    return render_template("admin/news_review.html", data=data)


# 新闻审核详情
@admin_blu.route("/news_review_detail/<int:news_id>")
def news_review_detail(news_id):
    # 根据新闻id查询新闻
    try:
        news = News.query.get(news_id)
    except BaseException as e:
        current_app.logger.error(e)
        return abort(500)

    # 传入模板渲染
    return render_template("admin/news_review_detail.html", news=news.to_dict())


# 新闻审核通过
@admin_blu.route("/news_review_action", methods=['POST'])
def news_review_action():
    # 获取参数
    news_id = request.json.get("news_id")
    action = request.json.get("action")
    # 校验参数
    if not all([news_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])
    if action not in ['accept', 'reject']:
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    try:
        news_id = int(news_id)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

        # 查看新闻类型
    try:
        news = News.query.get(news_id)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    # 修改新闻的状态
    if action == "accept":
        news.status = 0
    else:
        # 获取拒绝原因
        reason = request.json.get("reason")
        # if not reason:
        #     news.reason = None
        # else:
        #     news.reason = reason
        if reason:
            news.reason = reason
        news.status = -1

    # json返回结果
    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])


# 新闻版式编辑
@admin_blu.route("/news_edit")
def news_edit():
    # 请求钩子已经判断是否是管理员登录

    # 获取参数获取请求的第几页  默认为1
    p = request.args.get("p", 1)
    # 获取关键字
    keyword = request.args.get("keyword")

    # 校验参数
    try:
        p = int(p)
    except BaseException as e:
        current_app.logger.error(e)
        return abort(403)

    filter_list = []
    # 判断是否设置了关键字
    if keyword:
        # 有关键字就   添加到列表中    新闻标题中含有此keyword的新闻
        filter_list.append(News.title.contains(keyword))

    # 查询所有的新闻
    try:
        # 有条件按照条件，没有就查询所有
        pn = News.query.filter(*filter_list).paginate(p, USER_COLLECTION_MAX_NEWS)
    except BaseException as e:
        current_app.logger.error(e)

    # 转换数据
    data = {
        "news_list": [news.to_review_dict() for news in pn.items],  # 取出所有数据放到列表中，传给页面遍历
        "cur_page": pn.page,  # 当前页码
        "total_page": pn.pages  # 总页数
    }

    # 传入模板渲染
    return render_template("admin/news_edit.html", data=data)


# 新闻编辑详情
@admin_blu.route("/news_edit_detail")
def news_edit_detail():
    # 获取参数
    news_id = request.args.get("news_id")

    # 校验参数
    try:
        news_id = int(news_id)
    except BaseException as e:
        current_app.logger.error(e)
        return abort(403)

    # 根据新闻id查询新闻数据
    try:
        news = News.query.get(news_id)
    except BaseException as e:
        current_app.logger.error(e)
        return abort(500)

    # 查询所有的分类数据
    try:
        categories = Category.query.filter(Category.id != 1).all()
    except BaseException as e:
        current_app.logger.error(e)
        return abort(500)

    # 判断取出的分类是否为新闻当前的分类
    category_list = []
    for category in categories:
        category_dict = category.to_dict()
        is_selected = False
        # 判断取出的分类是否为新闻当前的分类
        if category.id == news.category_id:
            is_selected = True

        category_dict["is_selected"] = is_selected
        category_list.append(category_dict)

    # 传入模板
    return render_template("admin/news_edit_detail.html", news=news.to_dict(), category_list=category_list)


# 新闻编辑
@admin_blu.route("/news_edit_detail", methods=["POST"])
def news_edit_action():
    # 获取参数
    news_id = request.form.get("news_id")
    title = request.form.get("title")
    category_id = request.form.get("category_id")
    digest = request.form.get("digest")
    content = request.form.get("content")
    img_file = request.files.get("index_image")
    # 校验参数
    if not all([news_id, title, category_id, digest, content]):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    try:
        # 转换类型
        news_id = int(news_id)
        category_id = int(category_id)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])
    # 查询该新闻数据
    try:
        news = News.query.get(news_id)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    # 将获取到的数据 修改
    news.title = title
    news.category_id = category_id
    news.digest = digest
    news.content = content
    if img_file:  # 修改了图片
        try:
            # 读取图片二进制数据 传到七牛云
            img_bytes = img_file.read()
            file_name = file_upload(img_bytes)
            news.index_image_url = QINIU_DOMIN_PREFIX + file_name
        except BaseException as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.THIRDERR, errmsg=error_map[RET.THIRDERR])

    # json返回图片
    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])


# 新闻分类
@admin_blu.route("/news_type", methods=["GET", "POST"])
def news_type():
    # 展示页面
    if request.method == "GET":
        # 查询所有分类数据，传入模板
        try:
            categories = Category.query.filter(Category.id != 1).all()
        except BaseException as e:
            current_app.logger.error(e)
            return abort(500)

        return render_template("admin/news_type.html", categories=categories)

    # POST请求处理
    id = request.json.get("id")
    name = request.json.get("name")
    if not name:
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 修改分类
    if id:
        try:
            id = int(id)
            category = Category.query.get(id)
            category.name = name
        except BaseException as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    else:
        # 新增分类
        new_category = Category(name=name)
        # 添加到数据库
        db.session.add(new_category)

    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])
